#define _GNU_SOURCE
#include "app_common.h"
#include "app_device.h"
#include "app_message.h"

static Device_t devices[DRIVER_MAX_NUM];

// 读取上行缓冲区数据处理成json并发送
static int read_send_task(void *args)
{
    int device_index = *(int *)args;
    // 临时存储字符数组数据
    unsigned char data[128] = {0};
    // 读取缓冲区数据
    int data_len = app_buffer_read(devices[device_index].up_buffer, data, sizeof(data));
    // 若读取失败则返回
    if (data_len == -1)
    {
        log_error("read buffer failed");
        return -1;
    }
    else if (data_len > 0)
    {
        // 若读取成功则将数据转换成json并发送
        char *json = app_message_charsToJson((char *)data, data_len);
        app_mqtt_send(json, strlen(json));
        free(json);
    }
    return 0;
}

// 上行过程中读取文件数据任务
// 定义一个静态的void指针函数，用于读取线程任务
static void *read_thread_task(void *args)
{
    // 获取设备索引
    int device_index = *(int *)args;
    // 当设备正在运行时，循环读取数据
    while (devices[device_index].is_running)
    {
        // 定义一个字符数组，用于存储读取的数据
        unsigned char datas[128] = {0};
        // 读取文件数据
        ssize_t data_len = read(devices[device_index].fd, datas, sizeof(datas));
        // 如果读取的数据长度大于0，并且post_read_task不为空
        if (data_len > 0 && devices[device_index].post_read_task != NULL)
        {
            log_debug("UART read %s data_len = %d", datas, data_len);
            // 处理数据将文件数据转换成字符数组
            int chars_len = devices[device_index].post_read_task((unsigned char*)datas, (int)data_len);
            if (chars_len == 0)
            {
                log_debug("未收到完整数据");
            }
            else
            {
                // 将数据写入缓冲区
                app_buffer_write(devices[device_index].up_buffer, (unsigned char*)datas, chars_len);
                // 发送上传数据任务
                app_pool_resigterTask(read_send_task, (void *)&device_index);
            }
        }
        else if (data_len == -1)
        {
            log_error("read %s failed", devices[device_index].file_name);
            break;
        }
    }
    return NULL;
}

Device_t *app_device_init(char *file_name, int device_index)
{
    // 检查设备索引是否合法
    if (device_index >= DRIVER_MAX_NUM)
    {
        log_error("device_index is out of range");
        return NULL;
    }
    // 检查设备是否已经初始化
    if (devices[device_index].is_running)
    {
        log_error("device has been initialized");
        return NULL;
    }
    devices[device_index].is_running = 1;

    // 获取文件标识符
    int fd = open(file_name, O_RDWR);
    if (fd == -1)
    {
        log_error("open %s failed", file_name);
        return NULL;
    }
    // 初始化设备文件
    devices[device_index].file_name = file_name;
    devices[device_index].fd = fd;

    devices[device_index].last_writeTime = app_common_getTime();
    // 初始化数据处理函数
    devices[device_index].post_read_task = NULL;
    devices[device_index].pre_write_task = NULL;
    // 初始化双缓存区，大小为1024byte
    devices[device_index].up_buffer = app_buffer_init(1024);
    devices[device_index].down_buffer = app_buffer_init(1024);

    return &devices[device_index];
}

// 写入设备文件函数
static int write_file_task(void *args)
{
    int device_index = *(int *)args;
    // 临时存储字符数组数据
    unsigned char data[128] = {0};
    log_debug("开始读取数据");
    // 读取缓冲区数据,得到数据长度
    int data_len = app_buffer_read(devices[device_index].down_buffer, data, sizeof(data));
    for (int i = 0; i < data_len; i++)
    {
        log_debug("chars[%d]:%02x", i, data[i]);
    }
    // 若读取失败则返回
    if (data_len == -1)
    {
        log_error("read buffer failed");
        return -1;
    }
    if (data_len > 0 && devices[device_index].pre_write_task != NULL)
    {
        // 若读取成功,则判断上次写入时间
        long time = app_common_getTime();
        if ((time - devices[device_index].last_writeTime) < 200)
        {
            // 若间隔时间小于200ms，则等待
            usleep((200 - (time - devices[device_index].last_writeTime)) * 1000);
        }
        // 处理数据,将字符数组转换成文件数据格式
        int AT_len = devices[device_index].pre_write_task((unsigned char*)data, (int)data_len);
        for (int i = 0; i < AT_len; i++)
        {
            log_debug("AT[%d]:%02x", i, data[i]);
        }
        if (AT_len == -1)
        {
            log_error("pre_write_task failed");
            return -1;
        }
        // 更新时间戳
        devices[device_index].last_writeTime = app_common_getTime();
        // 写入设备文件
        write(devices[device_index].fd, data, AT_len);
    }
    free((int *)args);
    return 0;
}

// mqtt接收回调函数
static int receive_callback(char *data, int data_len)
{
    // 将接收到的数据转换成字符数组
    unsigned char chars[128] = {0};
    int chars_len = 0;           // 接收到的字符数据实际长度
    unsigned char conn_type = 0; // 连接类型,链接类型为设备 index + 1
    int *device_index = malloc(sizeof(int));
    chars_len = app_message_jsonToChars(data, (unsigned char*)chars, 128);
    for (int i = 0; i < chars_len; i++)
    {
        log_debug("chars[%d]:%02x", i, chars[i]);
    }
    if (chars_len == -1)
    {
        log_error("json to chars failed");
        return -1;
    }
    // 写入缓冲区
    if (chars_len > 0)
    {
        log_debug("chars_len:%d", chars_len);
        conn_type = chars[0];
        *device_index = conn_type - 1;
        log_debug("device_index:%d", *device_index);
        if (app_buffer_write(devices[*device_index].down_buffer, chars, chars_len) == -1)
        {
            log_error("write buffer failed");
            return -1;
        }
    }
    log_debug("写入完成");
    // 写入文件函数发给线程池执行
    app_pool_resigterTask(write_file_task, (void *)device_index);
    return 0;
}

/**
 * @brief 启动设备
 * @param device 设备地址
 * @return 0 成功，-1 失败
 */
int app_device_start(Device_t *device, int device_index)
{
    // 启动读取线程
    pthread_create(&device->read_thread, NULL, read_thread_task, (void *)&device_index);
    // 注册mqtt接收数据回调
    app_mqtt_resigterRecvCallBack(receive_callback);
    return 0;
}

/**
 * @brief 销毁设备
 * @param device 设备地址
 */
void app_device_destory(Device_t *device)
{
    device->is_running = 0;
    // 结束结束读取文件线程
    pthread_cancel(device->read_thread);
    // 关闭设备文件
    close(device->fd);
    // 释放缓冲区
    app_buffer_free(device->up_buffer);
    app_buffer_free(device->down_buffer);
}